/*
 * acooly.cn Inc.
 * Copyright (c) 2016 All Rights Reserved.
 * create by zhangpu 
 * date:2016年4月4日
 *
 */
package com.acooly.module.openapi.client.provider.newyl.marshall;

import com.acooly.core.utils.Strings;
import com.acooly.core.utils.validate.Validators;
import com.acooly.module.openapi.client.api.exception.ApiClientException;
import com.acooly.module.openapi.client.provider.newyl.NewYlConstants;
import com.acooly.module.openapi.client.provider.newyl.NewYlProperties;
import com.acooly.module.openapi.client.provider.newyl.domain.NewYlApiMessage;
import com.acooly.module.openapi.client.provider.newyl.domain.NewYlRequest;
import com.acooly.module.openapi.client.provider.newyl.signature.NewYlKeyStoreSigner;
import com.acooly.module.openapi.client.provider.newyl.support.NewYlKeyStoreInfo;
import com.acooly.module.openapi.client.provider.newyl.utils.StringHelper;
import com.acooly.module.safety.exception.SignatureVerifyException;
import com.acooly.module.safety.key.KeyLoadManager;
import com.acooly.module.safety.signature.SignerFactory;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;

/**
 * @author
 */
@Slf4j
public class NewYlMarshallSupport {

    @Autowired
    protected NewYlProperties newYlProperties;

    @Autowired
    protected SignerFactory signerFactory;

    @Autowired
    private KeyLoadManager keyStoreLoadManager;

    @Resource(name = "newYlKeyStoreSigner")
    private NewYlKeyStoreSigner newYlKeyStoreSigner;

    protected NewYlProperties getProperties() {
        return newYlProperties;
    }

    protected String doMarshall(NewYlRequest source) {
        doVerifyParam(source);
        newYlProperties.setPartnerId(source.getPartnerId());
        return getRequestMessage(source);
    }


    /**
     * 校验参数
     *
     * @param source
     */
    protected void doVerifyParam(NewYlApiMessage source) {
        try {
            source.doCheck();
            Validators.assertJSR303(source);
        } catch (Exception e) {
            throw new ApiClientException(e.getMessage());
        }
    }

    protected void beforeMarshall(NewYlApiMessage message) {
        if (Strings.isBlank(message.getPartnerId())) {
            message.setPartnerId(getProperties().getPartnerId());
        }
    }

    /**
     * 签名 优先获取传进来的，如果传进来没有则用配置文件中的
     *
     * @param source
     * @return
     */
    protected String getRequestMessage(NewYlRequest source) {
        String reqMsg = source.obj2Str(source).replaceAll("\r|\n", "").replaceAll(">  <", "><").replaceAll("  ", "").replaceAll("&lt;", "<").replaceAll("&gt;", ">");
        reqMsg = NewYlConstants.XML_HEAD + reqMsg;
        //去掉多余的字符
        try {
            Document doc = DocumentHelper.parseText(reqMsg);
            Element rootElt = doc.getRootElement();
            Element bodyElement = rootElt.element("BODY");
            String waitSignStr = StringHelper.asXml(bodyElement);
            log.info("待签字符串：{}",waitSignStr);
            String signStr = sign(waitSignStr, source);
            Element infoElement = rootElt.element("INFO");
            Element signElement = infoElement.addElement("SIGNED_MSG");
            signElement.setText(signStr);
            return NewYlConstants.XML_HEAD + rootElt.asXML();
        } catch (Exception e) {
            throw new ApiClientException("组装请求报文失败：" + e.getMessage());
        }
    }

    /**
     * 签名 优先获取传进来的，如果传进来没有则用配置文件中的
     *
     * @param waitForSign
     * @param source
     * @return
     */
    protected String sign(String waitForSign, NewYlRequest source) {
        NewYlKeyStoreInfo newYlKeyStoreInfo = getYlKeyStoreInfo(source.getPartnerId());
        String signStr = newYlKeyStoreSigner.sign(waitForSign, newYlKeyStoreInfo);
        return signStr;
    }

    /**
     * 验签
     *
     * @param plain
     * @return
     */
    protected void doVerifySign(String plain, String partnerId) {
        try {
            Document doc = DocumentHelper.parseText(plain);
            Element rootElt = doc.getRootElement();
            Element bodyElement = rootElt.element("BODY");
            String waitSignStr = StringHelper.asXml(bodyElement);
            Element infoElement = rootElt.element("INFO");
            Element signStrElement = infoElement.element("SIGNED_MSG");
            String signature = signStrElement.getText();
            NewYlKeyStoreInfo newYlKeyStoreInfo = getYlKeyStoreInfo(partnerId);
            newYlKeyStoreSigner.verify(waitSignStr, newYlKeyStoreInfo, signature);
            log.info("验签成功");
        }catch (Exception e) {
            throw new SignatureVerifyException(e.getMessage());
        }
    }
    /**
     * 获取keyStoreInfo
     *
     * @return
     */
    protected NewYlKeyStoreInfo getYlKeyStoreInfo(String partnerId) {
        NewYlKeyStoreInfo newYlKeyStoreInfo;
        try {
            newYlKeyStoreInfo = keyStoreLoadManager.load(partnerId, NewYlConstants.PROVIDER_NAME);
        } catch (Exception e) {
            synchronized (this) {
                log.info("商户partnerId={}密钥加载失败，启用配置文件密钥",partnerId);
                newYlKeyStoreInfo = new NewYlKeyStoreInfo();
                newYlKeyStoreInfo.setPrivateKeyUrl(newYlProperties.getPrivateCertPath());
                newYlKeyStoreInfo.setPublicKeyUrl(newYlProperties.getPublicCertPath());
                newYlKeyStoreInfo.setPlainEncode("GBK");
                newYlKeyStoreInfo.loadKeys();
            }
        }
        return newYlKeyStoreInfo;
    }
}